package com.yunlongn.common.json;

import com.yunlongn.common.json.config.JsonConfig;
import com.yunlongn.common.json.gson.GsonParser;
import com.yunlongn.common.json.jackson.JacksonParser;
import com.yunlongn.common.json.jackson.factory.AbstractJsonSerializer;
import com.yunlongn.common.json.util.StringUtils;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;



/**
 * json序列化适配器
 * @author Yun
 * @since 20210902
 */
public class JsonUtils {


    public static final AtomicReference<IJsonParser> JSON_PARSER_FACTORY
            = new AtomicReference<>(newJsonParserFactory(new JsonConfig()));

    private static IJsonParser newJsonParserFactory(JsonConfig config) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        try {
            classLoader.loadClass("com.google.gson.Gson");
            return new GsonParser(config);
        } catch (ClassNotFoundException e) {
            try {
                classLoader.loadClass("com.fasterxml.jackson.databind.ObjectMapper");
                return new JacksonParser(config);
            } catch (ClassNotFoundException ex) {
                throw new RuntimeException("未找到任何json包，请先在当前项目的依赖配置文件中加入 gson或fackson");
            }
        }
    }

    static {
        JSON_PARSER_FACTORY.set(newJsonParserFactory(new JsonConfig()));
    }

    public static synchronized void resetSerializeConfig(JsonConfig config) {
        JSON_PARSER_FACTORY.set(newJsonParserFactory(config));
    }

    public static <T> String toJsonString(T obj) {
        return toJsonString(obj, false, null);
    }

    public static <T> String toJsonString(T obj, boolean serializeNulls) {
        return toJsonString(obj, serializeNulls, null);
    }

    /**
     * 序列化
     * @param obj 序列化对象
     * @param serializeNulls 是否需要序列化值为null的字段
     * @param <T> 对象Class类型
     */
    public static <T> String toJsonString(T obj, boolean serializeNulls, String datePattern) {
        if (obj instanceof String) {
            return (String) obj;
        }
        if (obj == null) {
            return null;
        }
        return JSON_PARSER_FACTORY.get().toJsonString(obj, serializeNulls, datePattern);
    }
    public static <T> String toJsonString(T obj, Map<Class<?>, AbstractJsonSerializer<?>> jsonSerializerMap) {
        if (obj instanceof String) {
            return (String) obj;
        }
        if (obj == null) {
            return null;
        }
        return JSON_PARSER_FACTORY.get().toJsonString(obj, false, null, jsonSerializerMap);
    }

    public static <T> T fromJson(String jsonStr, Class<T> tClass) {
        if (StringUtils.isNullOrEmpty(jsonStr)) {
            return null;
        }
        if (tClass == String.class) {
            return (T) jsonStr;
        }
        return JSON_PARSER_FACTORY.get().fromJson(jsonStr, tClass);
    }

    public static <T> T fromJson(InputStream jsonIn, Class<T> tClass) {
        return JSON_PARSER_FACTORY.get().fromJson(jsonIn, tClass);
    }

    public static <T> T fromJson(String jsonStr, Type type) {
        return JSON_PARSER_FACTORY.get().fromJson(jsonStr, type);
    }

    public static <T> T fromJson(InputStream jsonIn, Type type) {
        return JSON_PARSER_FACTORY.get().fromJson(jsonIn, type);
    }

    public static <T> List<T> fromJsonArray(String jsonStr, TypeReference<List<T>> typeReference) {
        if (StringUtils.isNullOrEmpty(jsonStr)) {
            return null;
        }
        return JSON_PARSER_FACTORY.get().fromJsonArray(jsonStr, typeReference);
    }

    public static <K, V> Map<K, V> fromJsonMap(String jsonStr, TypeReference<Map<K, V>> typeReference) {
        if (StringUtils.isNullOrEmpty(jsonStr)) {
            return null;
        }
        return JSON_PARSER_FACTORY.get().fromJson(jsonStr, typeReference.getType());
    }

    public static <K, V> Map<K, V> fromJsonMap(InputStream jsonIn, TypeReference<Map<K, V>> typeReference) {
        return JSON_PARSER_FACTORY.get().fromJson(jsonIn, typeReference.getType());
    }
}
